// CPR库的响应类，用于处理HTTP请求的响应（状态码、返回内容等）
#include<cpr/response.h>
// Elasticsearch客户端库的核心类，提供操作ES的接口
#include<elasticlient/client.h>
#include<iostream>
#include<thread>

const std::string index_name = "student";  // 索引名（类似数据库的“表名”）
const std::string type_name = "_doc";      // 文档类型（ES 7.x后默认使用_doc）
const std::string index_id = "default_id"; // 默认文档ID（创建索引时的示例ID，实际新增数据时会指定其他ID）

//1.创建索引
void create_index(elasticlient::Client &client) {
    //1. 构造请求正文
    const std::string body = R"({
            "settings": {
                "analysis": {
                    "analyzer": {
                        "ikmax" : {
                            "type": "custom",
                            "tokenizer" : "ik_max_word"
                        }
                    }
                }
            },
            "mapping": {
                "dynamic": false,
                "properties": {
                    "name": {
                        "type": "text",
                        "boost": 3.0,
                        "analyzer": "ikmax"
                    },
                    "age": {
                        "type": "integer"
                    },
                    "phone": {
                        "type": "keyword", 
                        "boost": 1.0
                    },
                    "skills": { 
                        "type": "text"
                    },
                    "birth": {
                        "type": "date",
                        "index": false
                    }
                }
            }
        })";
	//2.发送创建索引请求
	auto resp = client.index(index_id, type_name, index_id, body);
	//3.获取结果判断是否创建索引成功 -- 判断响应状态码是否正常201
	if(resp.status_code < 200 || resp.status_code >= 300) {
		std::cout << "create index failed: " << resp.status_code << " " << resp.text << std::endl;
		return;
	}
}

//2.新增数据
//作用：向 student 索引中添加一条文档数据（类似数据库的 “插入行”）
void add_data(elasticlient::Client &client) {
	const std::string body = R"({
		"name": "刘大牙",
		"age": 19,
		"phone": "12552166666",
		"skills": ["C++","MySQL","Redis"],
		"birth": "1949-10-01 00:00:00"
	})";
	//发送新增请求
	//指定文档 ID 为 2
	//ES 中，index 方法若 ID 不存在则新增，若 ID 存在则全量替换（类似 “UPSERT”）
	auto resp = client.index(index_name, type_name, "2", body);
	if (resp.status_code < 200 || resp.status_code >= 300) {
        std::cout << "insert data failed: " << resp.status_code << " "<< resp.text << std::endl;
        return;
    }
}

//修改数据
void mod_data(elasticlient::Client &client) {
    const std::string body = R"({
        "name": "李四",
        "age": 19,
        "phone": "13333333333",
        "skills": ["java","php","go"],
        "birth": "2007-05-21 12:35:32"
    })";
    // 使用index方式进行更新，必须是全量更新，它等价于，先删除，再新增，如果不是全量更新，则最终就只有更新字段
    // const std::string body = R"({
    //     "name": "李四"
    // })";
    auto resp = client.index(index_name, type_name, "2", body);
    if (resp.status_code < 200 || resp.status_code >= 300) {
        std::cout << "insert data failed: " << resp.status_code << " "<< resp.text << std::endl;
        return;
    }
}

//删除数据
void remove_data(elasticlient::Client &client) {
    auto resp = client.remove(index_name, type_name, "2");
    if (resp.status_code < 200 || resp.status_code >= 300) {
        std::cout << "remove data failed: " << resp.status_code << " "<< resp.text << std::endl;
        return;
    }
}

//删除索引
void remove_index(elasticlient::Client &client) {
    auto resp = client.performRequest(elasticlient::Client::HTTPMethod::DELETE, index_name, "");
    if (resp.status_code < 200 || resp.status_code >= 300) {
        std::cout << "remove index failed: " << resp.status_code << " "<< resp.text << std::endl;
        return;
    }
}

//查询数据
void get_data(elasticlient::Client &client) {
    //match_all:全量查询
	const std::string body = R"(
        {
            "query" :  {
                "match_all" :   {}
            }
        }
    )";
    auto resp = client.search(index_name, type_name, body);
    if (resp.status_code < 200 || resp.status_code >= 300) {
        std::cout << "remove data failed: " << resp.status_code << " "<< resp.text << std::endl;
        return;
    }
    std::cout << "resp:" << resp.text << std::endl;
}

int main()
{
	//1.定义 ES 服务器地址
	const std::string url = "http://elastic:123456@192.168.8.128:9200/";
	// URL 格式：协议://用户名:密码@IP地址:端口/
	// elastic 是 ES 默认用户名，123456 是密码（需与 ES 配置一致）。
	// 192.168.8.128:9200 是 ES 服务器的 IP 和默认端口。

	//2.实例化 ES 客户端
	elasticlient::Client client({url});

	//3. 数据操作（创建索引，新增数据，全量查询，删除数据，删除索引）
	create_index(client);
    std::this_thread::sleep_for(std::chrono::seconds(1));//避免还未处理完毕休眠一下
    add_data(client);
    std::this_thread::sleep_for(std::chrono::seconds(1));
    mod_data(client);
    std::this_thread::sleep_for(std::chrono::seconds(1));
    get_data(client);
    remove_data(client);
    remove_index(client);
    return 0;
}